In Server Components, access params directly via the props object and await them in Next.js 15+; in Client Components, use the useParams() hook or receive params as props with React's use() to unwrap Promises
Accessing route parameters in Next.js App Router differs significantly between Server Components and Client Components, especially with the Next.js 15+ change that made params a Promise. Server Components receive params as a prop automatically and must await it . Client Components can either receive params as a prop (and unwrap with React's use() hook) or use the dedicated useParams() hook for direct synchronous access . The choice depends on whether the component needs to be interactive and whether it's rendered on the server or client.
Server Components: Params are received as a prop named params (a Promise in Next.js 15+) and must be awaited before use .
Client Components with useParams: Synchronous access anywhere in the component tree using the useParams() hook from next/navigation .
Client Components with props: Can receive params as a prop (as a Promise) and unwrap with React's use() hook .
Timing: Server Component params are available during server rendering; Client Component params are available after hydration .
When using useParams() in a Client Component, be aware that the component will be client-side rendered. If you're concerned about performance, you can still use Server Components for the main content and only use Client Components for interactive parts that need param access. Also note that in Next.js 15+, useParams() remains synchronous and does not return a Promise—it's designed for client-side use where the values are already known after hydration .
For query string parameters, the pattern is similar but uses searchParams in Server Components and useSearchParams() in Client Components. Note that useSearchParams() requires a Suspense boundary in static pages to prevent fully client-side rendering . The official Next.js documentation recommends wrapping components that use useSearchParams in a Suspense boundary to preserve static rendering for the rest of the page .